﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OracleClient;
using Kangaroo.Deferreds;
using Kangaroo.IDAL;
using Kangaroo.Model;
using System.Threading;

namespace Kangaroo.DAL.Oracle
{
    public class Signal : ISignal
    {
        public ChannelInfo[] ListChannels()
        {
            var reader = OracleHelper.ExecuteReader(OracleHelper.ConnectionString,
                CommandType.StoredProcedure, "CRUD_Channel.ListChannels",
                new OracleParameter("curChannel", OracleType.Cursor) { Direction = ParameterDirection.Output });
            var channels = new List<ChannelInfo>();
            while(reader.Read())
            {
                channels.Add(new ChannelInfo(
                    (int)(decimal)reader["Key"],
                    reader["DevId"] != DBNull.Value ? (string)reader["DevId"] : "未定义",
                    reader["DevChn"] != DBNull.Value ? (short)(decimal)reader["DevChn"] : (short)(decimal)(-1),
                    reader["EquipId"] != DBNull.Value ? (string)reader["EquipId"] : "未定义",
                    reader["EquipPhase"] != DBNull.Value ? (byte)(decimal)reader["EquipPhase"] : (byte)(decimal)255
                ));
            }
            reader.Close();
            return channels.ToArray();
        }

        public IDeferred<ChannelInfo[]> ListChannelsAsync()
        {
            return Deferred.New<ChannelInfo[]>(deferred => ThreadPool.QueueUserWorkItem(t =>
            {
                try
                {
                    var dataTable = ListChannels();
                    deferred.Resolve(dataTable);
                }
                catch (Exception exception)
                {
                    deferred.Reject(exception);
                }
            }));
        }

        public SignalInfo[] ListTimePointsOfChannel(ChannelInfo channel)
        {
            var reader = OracleHelper.ExecuteReader(OracleHelper.ConnectionString,
                CommandType.StoredProcedure, "CRUD_PD.ListTimePointsOfChannel",
                new OracleParameter("pChannelKey", channel.Key),
                new OracleParameter("curPoints", OracleType.Cursor) { Direction = ParameterDirection.Output });
            var timePoints = new List<SignalInfo>();
            while(reader.Read())
            {
                timePoints.Add(new SignalInfo
                {
                    Key = (Int64)(decimal)reader["Key"],
                    PdTime = (DateTime)reader["PDTime"]
                });
            }
            reader.Close();
            return timePoints.ToArray();
        }

        public SignalInfo[] ListSignalsOfChannel(ChannelInfo channel)
        {
            var reader = OracleHelper.ExecuteReader(OracleHelper.ConnectionString,
                CommandType.StoredProcedure, "CRUD_PD.ListSignalsOfChannel",
                new OracleParameter("pChannelKey", channel.Key),
                new OracleParameter("curPoints", OracleType.Cursor) { Direction = ParameterDirection.Output });
            var signals = new List<SignalInfo>();
            while (reader.Read())
            {
                signals.Add(ExtractSignalInfoFromReader(reader));
            }
            reader.Close();
            return signals.ToArray();
        }

        public SignalInfo GetSignal(Int64 key)
        {
            var signalInfo = GetSignalWithoutParsingGraph(key);
            signalInfo.PrpsGraph = new PrpsGraph(signalInfo.PrpsGraphRawData);
            return signalInfo;
        }

        public SignalInfo[] ListSignals()
        {
            var reader = OracleHelper.ExecuteReader(OracleHelper.ConnectionString,
                CommandType.StoredProcedure, "CRUD_PD.ListSignals",
                new OracleParameter("curSignals", OracleType.Cursor) { Direction = ParameterDirection.Output });
            var signals = new List<SignalInfo>();
            while(reader.Read())
            {
                signals.Add(ExtractSignalInfoFromReader(reader));
            }
            reader.Close();
            return signals.ToArray();
        }

        public DataTable ListSignalsByChannelWithinTime(int channelKey, DateTime startTime, DateTime endTime)
        {
            return OracleHelper.WithConnection(OracleHelper.ConnectionString, conn =>
            {
                var selectCommand = new OracleCommand("CRUD_PD.ListSignalsByChannelAndTime", conn)
                {
                    CommandType = CommandType.StoredProcedure
                };
                selectCommand.Parameters.Add(new OracleParameter("pChannelKey", channelKey));
                selectCommand.Parameters.Add(new OracleParameter("startTime", startTime));
                selectCommand.Parameters.Add(new OracleParameter("endTime", endTime));
                selectCommand.Parameters.Add(new OracleParameter("curSignals", OracleType.Cursor) { Direction = ParameterDirection.Output });
                var adapter = new OracleDataAdapter(selectCommand);
                var dataTable = new DataTable();
                adapter.Fill(dataTable);
                return dataTable;
            });
        }

        public IDeferred<SignalInfo[]> ListTimePointsOfChannelAsync(ChannelInfo channel)
        {
            return Deferred.New<SignalInfo[]>(deferred => ThreadPool.QueueUserWorkItem(t =>
            {
                try
                {
                    var dataTable = ListTimePointsOfChannel(channel);
                    deferred.Resolve(dataTable);
                }
                catch (Exception exception)
                {
                    deferred.Reject(exception);
                }
            }));
        }

        public IDeferred<SignalInfo[]> ListSignalsOfChannelAsync(ChannelInfo channel)
        {
            return Deferred.New<SignalInfo[]>(deferred => ThreadPool.QueueUserWorkItem(t =>
            {
                try
                {
                    var dataTable = ListTimePointsOfChannel(channel);
                    deferred.Resolve(dataTable);
                }
                catch (Exception exception)
                {
                    deferred.Reject(exception);
                }
            }));
        }

        public IDeferred<SignalInfo> GetSignalAsync(long key)
        {
            return Deferred.New<SignalInfo>(deferred => ThreadPool.QueueUserWorkItem(t =>
            {
                try
                {
                    var dataTable = GetSignal(key);
                    deferred.Resolve(dataTable);
                }
                catch (Exception exception)
                {
                    deferred.Reject(exception);
                }
            }));
        }

        public IDeferred<SignalInfo[]> ListSignalsAsync()
        {
            return Deferred.New<SignalInfo[]>(deferred => ThreadPool.QueueUserWorkItem(t =>
            {
                try
                {
                    var dataTable = ListSignals();
                    deferred.Resolve(dataTable);
                }
                catch (Exception exception)
                {
                    deferred.Reject(exception);
                }
            }));
        }

        public IDeferred<DataTable> ListSignalsByChannelWithinTimeAsync(int channelKey, DateTime startTime, DateTime endTime)
        {
            return Deferred.New<DataTable>(deferred => ThreadPool.QueueUserWorkItem(t =>
            {
                try
                {
                    var dataTable = ListSignalsByChannelWithinTime(channelKey, startTime, endTime);
                    deferred.Resolve(dataTable);
                }
                catch (Exception exception)
                {
                    deferred.Reject(exception);
                }
            }));
        }

        public SignalInfo GetSignalWithoutParsingGraph(long key)
        {
            var reader = OracleHelper.ExecuteReader(OracleHelper.ConnectionString,
                CommandType.StoredProcedure, "CRUD_PD.GetSignal",
                new OracleParameter("pKey", key),
                new OracleParameter("curSignal", OracleType.Cursor) { Direction = ParameterDirection.Output });
            SignalInfo signal = null;
            if(reader.Read())
            {
                signal = ExtractSignalInfoFromReader(reader);
            }
            reader.Close();
            return signal;
        }

        private static SignalInfo ExtractSignalInfoFromReader(OracleDataReader reader)
        {
            var signal = new SignalInfo
            {
                Key = (Int64)(decimal)reader["Key"],
                ChannelKey = (int)(decimal)reader["ChannelKey"],
                PdTime = (DateTime)reader["PDTime"],
                PdMean = (float)(decimal)reader["PDMean"],
                PdMax = (float)(decimal)reader["PDMax"],
                PdPhase = (float)(decimal)reader["PDPhase"],
                PdRep = (float)(decimal)reader["PDRep"],
                PdType = (string)reader["PDType"],
                PdTypeProb = (string)reader["PDTypeProb"],
                PdLoc = (string)reader["PDLoc"],
                PdLevel = (string)reader["PDLevel"],
                PdFile = (string)reader["PDFile"],
                PrpsGraphRawData = reader.HasColumn("PRPSGraph") ? (byte[])reader["PRPSGraph"] : null,
                Channel = new ChannelInfo(
                    (int)(decimal)reader["ChannelKey"],
                    reader["DevId"] != DBNull.Value ? (string)reader["DevId"] : "未定义",
                    reader["DevChn"] != DBNull.Value ? (short)(decimal)reader["DevChn"] : (short)(decimal)(-1),
                    reader["EquipId"] != DBNull.Value ? (string)reader["EquipId"] : "未定义",
                    reader["EquipPhase"] != DBNull.Value ? (byte)(decimal)reader["EquipPhase"] : (byte)(decimal)255)
            };
            return signal;
        }


        public ChannelInfo GetLatestChannel()
        {
            var reader = OracleHelper.ExecuteReader(OracleHelper.ConnectionString,
                CommandType.StoredProcedure, "CRUD_Channel.GetLatestChannel",
                new OracleParameter("curChannel", OracleType.Cursor) { Direction = ParameterDirection.Output });
            var channel = new ChannelInfo();
            if (reader.Read())
            {
                channel = new ChannelInfo(
                    (int)(decimal)reader["Key"],
                    reader["DevId"] != DBNull.Value ? (string)reader["DevId"] : "未定义",
                    reader["DevChn"] != DBNull.Value ? (short)(decimal)reader["DevChn"] : (short)(decimal)(-1),
                    reader["EquipId"] != DBNull.Value ? (string)reader["EquipId"] : "未定义",
                    reader["EquipPhase"] != DBNull.Value ? (byte)(decimal)reader["EquipPhase"] : (byte)(decimal)255
                );
            }
            reader.Close();
            return channel;
        }
    }
}
